﻿/*
 * Programer: JR Padfield
 * Description: Handles loading, changing maps client side.
 * Version: 1
 * Date: 12/17/13 * 
 */

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;

using GDIBitmap = System.Drawing.Bitmap;
using GDIGraphics = System.Drawing.Graphics;
using GDIGraphicsUnit = System.Drawing.GraphicsUnit;
using GDIImage = System.Drawing.Image;
using GDIRectangle = System.Drawing.Rectangle;
using TheWorldLibrary.Sprites;
using TheWorldLibrary.Characters;
using TheWorldLibrary.TileEngine;
using TheWorldLibrary.Worlds;
using TheWorldLibrary;
using Microsoft.Xna.Framework.Graphics;
using System.Windows.Forms;
using TheWorld.Global;
using TheWorld.GameScreens;


namespace TheWorld.Components
{
    public class Mapping
    {
        #region Fields

        private World World;
        private LevelData LevelData;
        private TileMap Map;
        private MapData MapData;
        private List<ILayer> layers = new List<ILayer>();
        private List<Tileset> tileSets = new List<Tileset>();
        private List<GDIImage> tileSetImages = new List<GDIImage>();
        private List<TilesetData> tileSetData = new List<TilesetData>();

        int _maxWidth;
        int _maxHeight;

        #endregion

        #region Constructor

        // Private Constructor
        private Mapping()
        {

        }

        // Singleton Accessor
        static Mapping instance;
        public static Mapping Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new Mapping();
                }
                return instance;
            }
        }

        #endregion

        #region Properties

        public World Worlds
        {
            get { return World; }
            set { World = value; }
        }

        public int MaxWidth
        {
            get { return _maxWidth; }
            set { _maxWidth = value; }
        }

        public int MaxHeight
        {
            get { return _maxHeight; }
            set { _maxHeight = value; }
        }

        #endregion

        #region Methods

        public void LoadMap(string mapName = "Starting Level")
        {
            LevelData newLevel = null;
            MapData = null;

            try
            {
                newLevel = XNASerializer.Deserialize<LevelData>(Application.StartupPath + @"\Content\Game\Levels\" + mapName + ".xml");
                MapData = XNASerializer.Deserialize<MapData>(Application.StartupPath + @"\Content\Game\Levels\Maps\" + newLevel.MapName + ".xml");

                tileSetImages.Clear();
                tileSetData.Clear();
                tileSets.Clear();
                layers.Clear();

                LevelData = newLevel;

                foreach (TilesetData data in MapData.Tilesets)
                {
                    Texture2D texture = null;

                    tileSetData.Add(data);

                    GDIImage image = (GDIImage)GDIBitmap.FromFile(Application.StartupPath + @"\Content\Tiles\" + data.TilesetImageName);
                    tileSetImages.Add(image);

                    using (Stream stream = new FileStream(Application.StartupPath + @"\Content\Tiles\" + data.TilesetImageName, FileMode.Open, FileAccess.Read))
                    {
                        texture = Texture2D.FromStream(Client.graphics.GraphicsDevice, stream);
                        tileSets.Add(new Tileset(
                            texture,
                            data.TilesWide,
                            data.TilesHigh,
                            data.TileWidthInPixels,
                            data.TileHeightInPixels));
                    }
                }

            

                foreach (MapLayerData data in MapData.Layers)
                {
                    layers.Add(MapLayer.FromMapLayerData(data));
                }

                Map = new TileMap(tileSets[0], (MapLayer)layers[0]);
                
                for (int t = 1; t < tileSets.Count; t++)
                {
                    Map.AddTileset(tileSets[t]);
                }

                for (int l = 1; l < layers.Count; l++)
                {
                    Map.AddLayer(layers[l]);
                }

                var levels = new Level(Map, newLevel.MapWidth, newLevel.MapHeight);

                Worlds = new World(BaseGameState.GameRef, BaseGameState.GameRef.ScreenRectangle);

                _maxWidth = newLevel.MapWidth;
                _maxHeight = newLevel.MapHeight;

                Worlds.Levels.Add(levels);
                
                Mapping.Instance.Worlds.CurrentLevel = 0;
                Worlds.Levels[Worlds.CurrentLevel].MaxHeight = newLevel.MapHeight;
                Worlds.Levels[Worlds.CurrentLevel].MaxWidth = newLevel.MapWidth;
                Worlds.Levels[Worlds.CurrentLevel].Characters.Add(null);

                // Add attributes to the new level
                // All attributes must be on layer 2
                for (var y = 0; y < newLevel.MapHeight; y++)
                {
                    for (var x = 0; x < newLevel.MapWidth; x++)
                    {
                        Debug.Write(MapData.Layers[0].GetAttribute(x,y).attribute + Environment.NewLine);
                        Worlds.Levels[Worlds.CurrentLevel].SetAttributeTile(x, y, MapData.Layers[0].GetAttribute(x,y).attribute);
                    }
                }
            }
            catch (Exception ex)
            {
                //MessageBox.Show(ex.Message, "Error Loading Maps");
                Console.WriteLine(ex.Message, "Error reading map");
            }
        }

        public void AddCharacter(string name, string entityClass, int genders, int spritenum, int index)
        {
            Dictionary<AnimationKey, Animation> animations = new Dictionary<AnimationKey, Animation>();

            Animation animation = new Animation(3, 32, 32, 0, 0);
            animations.Add(AnimationKey.Down, animation);

            animation = new Animation(3, 32, 32, 0, 32);
            animations.Add(AnimationKey.Left, animation);

            animation = new Animation(3, 32, 32, 0, 64);
            animations.Add(AnimationKey.Right, animation);

            animation = new Animation(3, 32, 32, 0, 96);
            animations.Add(AnimationKey.Up, animation);

            AnimatedSprite sprite = new AnimatedSprite(
                GfxManager.Instance.Sprites[spritenum],
                animations);

            EntityGender gender;
            if (genders == 1)
            {
                gender = EntityGender.Male;
            }
            else
            {
                gender = EntityGender.Female;
            }

            Entity entity = new Entity(
                name,
                DataManager.EntityData[entityClass],
                gender,
                EntityType.Character);

            Character newChar = new Character(entity, sprite);


            World.Levels[Mapping.Instance.Worlds.CurrentLevel].Characters.Insert(index, newChar);
            // Force update the player when added to make them show on the correct place on the map.
            World.Levels[Mapping.Instance.Worlds.CurrentLevel].Characters[index].Update(Static._gameTime);
        }

        #region Checks

        public bool CheckBlockedTile(int x, int y)
        {
            if (x == -1)
            {
                x = 0;
            }
            if (y == -1)
            {
                y = 0;
            }

            if (x >= 0 && y >= 0)
            {
                if (Mapping.Instance.Worlds.Levels[Mapping.Instance.Worlds.CurrentLevel].GetAttribute(x, y).attribute.Equals(1))
                {
                    // blocked tile
                    return true;
                }
                else
                {
                    return false;
                }
            }

            return false;
        }

        #endregion

        #endregion
    }
}
